﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Text.Json;

namespace PmSoft.Core.EventBus;

/// <summary>
/// 本地事件总线实现类，提供同步、异步和火即忘的事件发布功能。
/// 支持同步处理器 <see cref="IEventHandler{TEvent}"/> 和异步处理器 <see cref="IAsyncEventHandler{TEvent}"/>。
/// 通过批量处理优化性能，并确保所有异常被捕获和记录。
/// </summary>
public class LocalEventBus : IEventBus, IDisposable
{
	private readonly IServiceScopeFactory _scopeFactory;
	private readonly ILogger<LocalEventBus> _logger;
	private readonly ConcurrentQueue<(Type EventType, CommonEventArgs EventArgs)> _eventQueue;
	private readonly CancellationTokenSource _cts;
	private readonly Task _batchProcessingTask;
	private readonly int _batchSize;
	private readonly TimeSpan _batchInterval;
	private readonly TimeSpan _expectedHandlerDuration;

	/// <summary>
	/// 初始化 <see cref="LocalEventBus"/> 类的新实例。
	/// </summary>
	/// <param name="scopeFactory">服务范围工厂，用于解析事件处理器。</param>
	/// <param name="logger">日志记录器，用于记录异常和调试信息。</param>
	/// <param name="batchSize">批量处理的事件数量，默认值为 100。</param>
	/// <param name="batchInterval">批量处理的时间间隔，默认值为 1 秒。</param>
	/// <param name="expectedHandlerDuration">处理器预期执行时长，默认值为 60 秒，用于监控。</param>
	public LocalEventBus(IServiceScopeFactory scopeFactory, ILogger<LocalEventBus> logger,
		int batchSize = 100, TimeSpan? batchInterval = null, TimeSpan? expectedHandlerDuration = null)
	{
		_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
		_logger = logger ?? throw new ArgumentNullException(nameof(logger));
		_eventQueue = new ConcurrentQueue<(Type, CommonEventArgs)>();
		_cts = new CancellationTokenSource();
		_batchSize = Math.Max(1, batchSize);
		_batchInterval = batchInterval ?? TimeSpan.FromSeconds(1);
		_expectedHandlerDuration = expectedHandlerDuration ?? TimeSpan.FromSeconds(60);
		_batchProcessingTask = Task.Run(ProcessBatchEventsAsync, _cts.Token);
	}

	/// <summary>
	/// 同步发布事件，阻塞执行所有同步处理器。
	/// </summary>
	/// <typeparam name="TEvent">事件参数类型，必须继承自 <see cref="CommonEventArgs"/>。</typeparam>
	/// <param name="args">事件参数实例。</param>
	public void Publish<TEvent>(TEvent args) where TEvent : CommonEventArgs
	{
		if (args == null) throw new ArgumentNullException(nameof(args));

		using var scope = _scopeFactory.CreateScope();
		var handlers = scope.ServiceProvider.GetServices<IEventHandler<TEvent>>();

		if (!handlers.Any())
		{
			_logger.LogDebug("未找到事件 {EventType} 的同步处理器", typeof(TEvent).Name);
			return;
		}

		foreach (var handler in handlers)
		{
			try
			{
				handler.Handle(args);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "同步处理事件 {EventType} 时发生异常，处理器: {HandlerType}",
					typeof(TEvent).Name, handler.GetType().Name);
			}
		}
	}

	/// <summary>
	/// 异步发布事件，等待所有异步处理器完成。
	/// </summary>
	/// <typeparam name="TEvent">事件参数类型，必须继承自 <see cref="CommonEventArgs"/>。</typeparam>
	/// <param name="args">事件参数实例。</param>
	/// <returns>表示异步操作的任务。</returns>
	public async Task PublishAsync<TEvent>(TEvent args) where TEvent : CommonEventArgs
	{
		if (args == null) throw new ArgumentNullException(nameof(args));

		using var scope = _scopeFactory.CreateScope();
		var handlers = scope.ServiceProvider.GetServices<IAsyncEventHandler<TEvent>>().ToList();

		if (handlers.Count == 0)
		{
			_logger.LogDebug("未找到事件 {EventType} 的异步处理器", typeof(TEvent).Name);
			return;
		}

		var tasks = new List<Task>(handlers.Count);
		var startTimes = new List<DateTime>(handlers.Count);
		foreach (var handler in handlers)
		{
			try
			{
				var task = handler.HandleAsync(args);
				tasks.Add(task);
				startTimes.Add(DateTime.UtcNow);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "异步处理事件 {EventType} 时发生同步异常，处理器: {HandlerType}",
					typeof(TEvent).Name, handler.GetType().Name);
			}
		}

		if (tasks.Count == 0)
		{
			_logger.LogWarning("事件 {EventType} 无有效异步处理器，所有处理器调用均失败", typeof(TEvent).Name);
			return;
		}

		await ExecuteTasksAsync(tasks, handlers, startTimes, typeof(TEvent).Name);
	}

	/// <summary>
	/// 发布事件并立即返回，事件处理在后台批量执行。
	/// </summary>
	/// <typeparam name="TEvent">事件参数类型，必须继承自 <see cref="CommonEventArgs"/>。</typeparam>
	/// <param name="args">事件参数实例。</param>
	public void FireAndForget<TEvent>(TEvent args) where TEvent : CommonEventArgs
	{
		if (args == null) throw new ArgumentNullException(nameof(args));

		var clonedEvent = CloneEvent(args);
		_eventQueue.Enqueue((typeof(TEvent), clonedEvent));
	}

	/// <summary>
	/// 后台任务，批量处理队列中的事件。
	/// </summary>
	private async Task ProcessBatchEventsAsync()
	{
		while (!_cts.IsCancellationRequested)
		{
			try
			{
				if (_eventQueue.IsEmpty)
				{
					await Task.Delay(_batchInterval, _cts.Token);
					continue;
				}

				var batch = new List<(Type EventType, CommonEventArgs EventArgs)>(_batchSize);
				while (_eventQueue.TryDequeue(out var item) && batch.Count < _batchSize)
				{
					batch.Add(item);
				}

				if (batch.Count == 0) continue;

				using var scope = _scopeFactory.CreateScope();
				var provider = scope.ServiceProvider;

				var allTasks = new List<Task>();
				var allHandlers = new List<object>();
				var allStartTimes = new List<DateTime>();

				foreach (var (eventType, eventArgs) in batch)
				{
					var handlers = GetAsyncHandlersForEvent(provider, eventType);
					if (handlers.Length == 0)
					{
						_logger.LogDebug("未找到事件 {EventType} 的异步处理器", eventType.Name);
						continue;
					}

					foreach (var handler in handlers)
					{
						try
						{
							var task = InvokeAsyncHandler(handler, eventArgs);
							allTasks.Add(task);
							allHandlers.Add(handler);
							allStartTimes.Add(DateTime.UtcNow);
						}
						catch (Exception ex)
						{
							_logger.LogError(ex, "批量处理事件 {EventType} 时发生同步异常，处理器: {HandlerType}",
								eventType.Name, handler.GetType().Name);
						}
					}
				}

				if (allTasks.Count > 0)
				{
					await ExecuteTasksAsync(allTasks, allHandlers, allStartTimes, "批量事件");
				}

				if (_eventQueue.IsEmpty)
				{
					await Task.Delay(_batchInterval, _cts.Token);
				}
			}
			catch (OperationCanceledException)
			{
				_logger.LogInformation("批量事件处理任务已取消");
				break;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "批量事件处理循环异常");
				await Task.Delay(_batchInterval, _cts.Token);
			}
		}
	}

	/// <summary>
	/// 执行任务并处理异常和长时间运行的任务。
	/// </summary>
	private async Task ExecuteTasksAsync<THandler>(List<Task> tasks, List<THandler> handlers,
		List<DateTime> startTimes, string eventDescription)
	{
		try
		{
			await Task.WhenAll(tasks);
		}
		catch (Exception)
		{
			// 异常会在后续检查中处理
		}

		for (int i = 0; i < tasks.Count; i++)
		{
			var task = tasks[i];
			var handler = handlers[i];
			var duration = DateTime.UtcNow - startTimes[i];

			if (task.IsFaulted && task.Exception != null)
			{
				_logger.LogError(task.Exception, "处理 {EventDescription} 时发生异常，处理器: {HandlerType}, 耗时: {Duration}ms",
					eventDescription, handler!.GetType().Name, duration.TotalMilliseconds);
			}
			else if (duration > _expectedHandlerDuration)
			{
				_logger.LogWarning("处理器 {HandlerType} 处理 {EventDescription} 耗时过长: {Duration}ms",
					handler!.GetType().Name, eventDescription, duration.TotalMilliseconds);
			}
		}
	}

	/// <summary>
	/// 动态获取异步处理器实例。
	/// </summary>
	private object[] GetAsyncHandlersForEvent(IServiceProvider provider, Type eventType)
	{
		var handlerType = typeof(IAsyncEventHandler<>).MakeGenericType(eventType);
		return provider.GetServices(handlerType).ToArray()!;
	}

	/// <summary>
	/// 动态调用异步处理器的 HandleAsync 方法。
	/// </summary>
	private Task InvokeAsyncHandler(object handler, CommonEventArgs args)
	{
		var method = handler.GetType().GetMethod("HandleAsync")!;
		return (Task)method.Invoke(handler, new[] { args })!;
	}

	/// <summary>
	/// 创建事件对象的深拷贝。
	/// </summary>
	private TEvent CloneEvent<TEvent>(TEvent args) where TEvent : CommonEventArgs
	{
		try
		{
			var json = JsonSerializer.Serialize(args);
			return JsonSerializer.Deserialize<TEvent>(json)!;
		}
		catch (Exception ex)
		{
			_logger.LogError(ex, "事件 {EventType} 深拷贝失败，返回原始对象", typeof(TEvent).Name);
			return args;
		}
	}

	/// <summary>
	/// 释放资源，停止后台任务。
	/// </summary>
	public void Dispose()
	{
		_cts.Cancel();
		try
		{
			_batchProcessingTask.Wait(5000);
		}
		catch (Exception ex)
		{
			_logger.LogWarning(ex, "停止批量处理任务时发生异常");
		}
		finally
		{
			_cts.Dispose();
		}
	}
}

 